
#include "i2c_slave.h"

#include <crc_check.h>
#include <py32f002b_hal_cortex.h>

#include "py32f002b_ll_i2c.h"
#include "py32f002b_ll_gpio.h"
#include "py32f002b_ll_bus.h"
#include "string.h"


struct I2CSlaveInitParam g_I2C1SlaveInitParam = {};

struct I2CSlaveDummyRegister *g_I2C1SlaveDummyRegister = NULL;
uint8_t g_I2C1SlaveDummyRegisterSize = 0;

uint8_t g_IsI2C1Init = 0;

int32_t I2C1_SlaveInit(const struct I2CSlaveInitParam *paramm,
                       struct I2CSlaveDummyRegister *dummyReg,
                       uint8_t dummyRegSize) {
    //检查参数
    if (paramm == NULL || dummyReg == NULL || dummyRegSize == 0) {
        printf("%s Param error\r\n", __func__);
        return -1;
    }

    //如果已经初始化,先释放资源
    if (g_IsI2C1Init == 1) {
        I2C1_SlaveDeinit();
    }

    g_I2C1SlaveInitParam = *paramm;
    g_I2C1SlaveDummyRegister = dummyReg;
    g_I2C1SlaveDummyRegisterSize = dummyRegSize;

    //配置i2c使用的gpio
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
    if (g_I2C1SlaveInitParam.gpioPort == GPIOA) {
        LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
    } else if (g_I2C1SlaveInitParam.gpioPort == GPIOB) {
        LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
    } else if (g_I2C1SlaveInitParam.gpioPort == GPIOC) {
        LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOC);
    } else {
        printf("UnSupport GPIO Port: %p \r\n", g_I2C1SlaveInitParam.gpioPort);
        return -2;
    }
    GPIO_InitStruct.Pin = g_I2C1SlaveInitParam.gpioPin;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
    GPIO_InitStruct.Alternate = LL_GPIO_AF_6;
    LL_GPIO_Init(g_I2C1SlaveInitParam.gpioPort, &GPIO_InitStruct);

    //配置i2c1
    LL_I2C_InitTypeDef I2C_InitStruct = {0};
    LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);

    NVIC_SetPriority(I2C1_IRQn, 0);
    NVIC_EnableIRQ(I2C1_IRQn);

    LL_I2C_DisableGeneralCall(I2C1);
    LL_I2C_EnableClockStretching(I2C1);
    I2C_InitStruct.ClockSpeed = g_I2C1SlaveInitParam.freq;
    I2C_InitStruct.DutyCycle = LL_I2C_DUTYCYCLE_2;
    I2C_InitStruct.OwnAddress1 = g_I2C1SlaveInitParam.address;
    I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
    LL_I2C_Init(I2C1, &I2C_InitStruct);
    LL_I2C_EnableBitPOS(I2C1);

    //使能i2c中断
    LL_I2C_Enable(I2C1);
    LL_I2C_EnableIT_ERR(I2C1); //使能错误中断
    LL_I2C_EnableIT_EVT(I2C1); //使能事件中断

    g_IsI2C1Init = 1;

    return 0;
}

void I2C1_SlaveDeinit(void) {
    if (g_IsI2C1Init == 0) {
        printf("%s I2c1 is already deinit\r\n", __func__);
        return;
    }

    LL_I2C_Disable(I2C1);
    LL_I2C_DisableIT_ERR(I2C1); //使能错误中断
    LL_I2C_DisableIT_EVT(I2C1); //使能事件中断
    NVIC_DisableIRQ(I2C1_IRQn);

    LL_I2C_DeInit(I2C1);
    LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_I2C1);

    LL_GPIO_DeInit(g_I2C1SlaveInitParam.gpioPort);
    if (g_I2C1SlaveInitParam.gpioPort == GPIOA) {
        LL_IOP_GRP1_DisableClock(LL_IOP_GRP1_PERIPH_GPIOA);
    } else if (g_I2C1SlaveInitParam.gpioPort == GPIOB) {
        LL_IOP_GRP1_DisableClock(LL_IOP_GRP1_PERIPH_GPIOB);
    } else if (g_I2C1SlaveInitParam.gpioPort == GPIOC) {
        LL_IOP_GRP1_DisableClock(LL_IOP_GRP1_PERIPH_GPIOC);
    }
    g_IsI2C1Init = 0;
}

void I2C1_Reset() {
    if (g_IsI2C1Init == 1) {
        //反初始化i2c1
        LL_I2C_DeInit(I2C1);

        //初始化i2c1
        //配置i2c1
        LL_I2C_InitTypeDef I2C_InitStruct = {0};
        LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);

        NVIC_SetPriority(I2C1_IRQn, 0);
        NVIC_EnableIRQ(I2C1_IRQn);

        LL_I2C_DisableGeneralCall(I2C1);
        LL_I2C_EnableClockStretching(I2C1);
        I2C_InitStruct.ClockSpeed = g_I2C1SlaveInitParam.freq;
        I2C_InitStruct.DutyCycle = LL_I2C_DUTYCYCLE_2;
        I2C_InitStruct.OwnAddress1 = g_I2C1SlaveInitParam.address;
        I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
        LL_I2C_Init(I2C1, &I2C_InitStruct);
        LL_I2C_EnableBitPOS(I2C1);

        //使能i2c中断
        LL_I2C_Enable(I2C1);
        LL_I2C_EnableIT_ERR(I2C1); //使能错误中断
        LL_I2C_EnableIT_EVT(I2C1); //使能事件中断

    }
}

// 1.地址匹配中断触发
// 2.如果主机读,则开启从机发送中断; 如果主机写,则开启从机接收中断
// 3.从机接收中断第一次触发,读取主机发送的第一个字节为虚拟寄存器地址
// 4.如果虚拟寄存器地址匹配成功,则设置g_CurrentI2CSlaveDummyRegister

void I2C1_IRQHandler(void) {

    static uint8_t isI2C1RegAddrRecv = 0;
    static uint8_t i2c1RegisterRWCnt = 0;
    static uint8_t i2c1RecvDataTemp[MAX_REG_DATA_SIZE + 1] = {};
    static uint8_t i2c1CurrentDummyRegisterIdx = 0; //默认读取第0个寄存器

    //1.读状态寄存器
    uint32_t itsource = READ_REG(I2C1->CR1);

    uint32_t sr2itflags = READ_REG(I2C1->SR2);
    uint32_t sr1itflags = READ_REG(I2C1->SR1);

    UNUSED(sr2itflags);
    UNUSED(itsource);

    if (I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_ADDR) != RESET) {
        //地址匹配中断发生
        LL_I2C_ClearFlag_ADDR(I2C1);
        //检查主机读写标志
        if (LL_I2C_GetTransferDirection(I2C1) == LL_I2C_DIRECTION_READ) {
            //主机写,从机收
            LL_I2C_EnableIT_RX(I2C1); //使能从机接收中断
            isI2C1RegAddrRecv = 0;
            i2c1RegisterRWCnt = 0;
        } else {
            //主机读,从机发
            LL_I2C_EnableIT_TX(I2C1); //使能从机发送中断
            i2c1RegisterRWCnt = 0; //主机准备读取了,将读写计数清零
        }
    } else if (I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_RXNE) != RESET) {
        //从机接收中断发生,准备读取来自主机的数据 第一个字节作为 addr
        uint8_t recvData = LL_I2C_ReceiveData8(I2C1);
        if (isI2C1RegAddrRecv == 0) {
            //第一次接收数据,判断是否是正确的地址
            for (int32_t i = 0; i < g_I2C1SlaveDummyRegisterSize; i++) {
                if (recvData == g_I2C1SlaveDummyRegister[i].addr) {
                    isI2C1RegAddrRecv = 1; //匹配到了正确的Dummy寄存器地址
                    i2c1CurrentDummyRegisterIdx = i; //保存当前的Dummy寄存器索引
                    break;
                }
            }
            if (isI2C1RegAddrRecv == 0) {
                //没有正确的写入地址,取消本次传输
                I2C1_Reset();
            }
        } else {
            //第二次接收数据,将数据更新到Register
            //1.检查地址匹配是否成功
            //2.检查该虚拟寄存器是否可读写
            if (isI2C1RegAddrRecv == 1 && g_I2C1SlaveDummyRegister[i2c1CurrentDummyRegisterIdx].isReadOnly != 1) {
                if (i2c1RegisterRWCnt < MAX_REG_DATA_SIZE) { //只处理我们需要的几个数据,主机多发的数据全部丢弃
                    i2c1RecvDataTemp[i2c1RegisterRWCnt++] = recvData; //数据先保存到临时缓冲区
                } else if (i2c1RegisterRWCnt == MAX_REG_DATA_SIZE) { //第4+1个字节是crc校验码
                    //需要的数据传输完成,计算CRC
                    //数据接收完毕,计算本次传输的CRC是否合法
                    uint8_t crc = Crc8_Calculate(i2c1RecvDataTemp, MAX_REG_DATA_SIZE);
                    if (crc == recvData) {
                        //CRC校验通过,更新寄存器
                        memcpy(g_I2C1SlaveDummyRegister[i2c1CurrentDummyRegisterIdx].data, i2c1RecvDataTemp, MAX_REG_DATA_SIZE);
                        g_I2C1SlaveDummyRegister[i2c1CurrentDummyRegisterIdx].isUpdate = 1;
                    }
                }
            }else {
                //该虚拟寄存器是只读的,结束本次I2C通信
                I2C1_Reset();
            }
        }
    } else if (I2C_CHECK_FLAG(sr1itflags, I2C_FLAG_TXE) != RESET) {
        //从机发送中断发生,准备将数据发送给主机
        if (i2c1RegisterRWCnt < MAX_REG_DATA_SIZE) {
            uint8_t sendData = g_I2C1SlaveDummyRegister[i2c1CurrentDummyRegisterIdx].data[i2c1RegisterRWCnt++];
            LL_I2C_TransmitData8(I2C1, sendData);
        } else if ( i2c1RegisterRWCnt == MAX_REG_DATA_SIZE ) {
            //计算, 发送crc
            uint8_t crc = Crc8_Calculate(g_I2C1SlaveDummyRegister[i2c1CurrentDummyRegisterIdx].data, MAX_REG_DATA_SIZE);
            LL_I2C_TransmitData8(I2C1, crc);
            i2c1RegisterRWCnt++;
        } else {
            LL_I2C_TransmitData8(I2C1, 0x00); //主机收的数据超过了限制,从机全部发0x00给主机
        }
    } else {
        //本次i2c传输结束 or 有错误发生, 重置i2c
        isI2C1RegAddrRecv = 0;
        i2c1RegisterRWCnt = 0;
        I2C1_Reset();
    }
}
